# This module defines a service that manages and provides an interface 
# to the the wxPython tasklet

from __future__ import print_function
from __future__ import absolute_import

import wx
import logging

from kharlia import core

class CWXService(core.CTaskletService):
    Name = 'WX Service'
    Depends = []
    
    def __init__(self, *args, **kwds):
        core.CTaskletService.__init__(self, *args, **kwds)
        self.WXApp = None
        self.Logger = logging.getLogger('wxinter')
        
    @property
    def IsStarted(self):
        return self._IsStarted and self.WXApp
        
    def CreateTopWindow(self, winclass, *args, **kwds):
        '''
        Interface for wx.App.CreateTopWindow().
        
        This is the entry point for GUI use.
        '''
        assert self.IsStarted
        assert self.WXApp is not None
        if not issubclass(winclass, wx.Window):
            raise TypeError('winclass must be a subclass of wx.Window')
        if self.WXApp.GetTopWindow() is not None:
            raise RuntimeError('a top window already exists')
            
        window = winclass(*args, **kwds)
        window.Show()
        self.WXApp.SetTopWindow(window)
        return window

    def DestroyTopWindow(self):
        '''Destroy the top window when GUI application is done.'''
        assert self.IsStarted
        win = self.WXApp.GetTopWindow()
        if win is not None:
            win.Destroy()

    def TaskletMain(self):
        '''
        WXService tasklet entry point.
        
        This sets up a wxPython event loop and processes events.
        Killing this tasklet will shut down the wxPython application.
        '''
        logger = self.Logger
        try:
            # Create the app
            logger.debug('initializing WXApp')
            self.WXApp = wxa = wx.App(redirect=False)

            # Activate our event loop
            if wx.EventLoop.GetActive() is not None:
                logger.warning('replacing already active event loop')
            evt = wx.EventLoop()
            act = wx.EventLoopActivator(evt)
            
            # Shortcuts
            yield_ = core.Yield
            pending = evt.Pending
            dispatch = evt.Dispatch
            procidle = wxa.ProcessIdle
            while 1:
                while pending():
                    dispatch()
                else:
                    procidle()
                yield_()
                
        finally:
            self.DestroyTopWindow()
            if self.WXApp is not None:
                self.WXApp.ProcessIdle() # process window destruction
                self.WXApp.Destroy()
                self.WXApp = None